/*********************
* Author:Dzlua
* QQ:505544956
* time:2016/08/13
*/
#include "Font.h"
#include "../edui_sdl.h"

EDUI_NAMESPACE_BEGIN

#ifdef EDUI_TEST_NEW_DELETE
int Font::m_newdeleteNum = 0;
int Font::_GetNewDeleteNum()
{
    return m_newdeleteNum;
}
#endif

Font::Font() : m_font(0)
{}

Font::~Font()
{
    this->Destroy();
}

Font* Font::GetInterface()
{
    Font* font = new Font;
#ifdef EDUI_TEST_NEW_DELETE
    ++m_newdeleteNum;
    Log("[Font] new font : %d", font);
#endif
#ifdef EDUI_USE_LUAPLUS
    LuaMgrPtr->Add("Font", font);
#endif
    return font;
}

void Font::Release()
{
#ifdef EDUI_TEST_NEW_DELETE
    --m_newdeleteNum;
    Log("[Font] delete font : %d", this);
#endif
#ifdef EDUI_USE_LUAPLUS
    LuaMgrPtr->Remove(this);
#endif
    delete this;
}

Font* Font::ToFont(IFont* font)
{
    return dynamic_cast<Font*>(font);
}

bool Font::Create(const char* file, int size, const char* name, int id)
{
    if (!file) return false;
    FontMgr* mgr = IEnginePtr->GetFontMgr();
    
    m_font = TTF_OpenFont(file, size);
    if (!m_font) return false;
    
    if (!name){
        String str;
        str.Format("%s-%d", file, size);
        if (!mgr->Add(str.GetString(), this, id)){
            this->Destroy();
            return false;
        }
    } else {
        if (!mgr->Add(name, this, id)){
            this->Destroy();
            return false;
        }
    }
    return true;
}

bool Font::Create(const char* file, int size, long idx, const char* name, int id)
{
    if (!file) return false;
    FontMgr* mgr = IEnginePtr->GetFontMgr();
    
    m_font = TTF_OpenFontIndex(file, size, idx);
    if (!m_font) return false;
    
    if (!name){
        String str;
        str.Format("%s-%d-%d", file, size, idx);
        if (!mgr->Add(str, this, id)){
            this->Destroy();
            return false;
        }
    } else {
        if (!mgr->Add(name, this, id)){
            this->Destroy();
            return false;
        }
    }
    return true;
}

// create use this function, you must Destroy and Release this font.
bool Font::Create(TTF_Font* font)
{
    if (this->IsOK()) return false;
    if (!font) return false;
    m_font = font;
    return true;
}

bool Font::IsOK()
{
    return !!m_font;
}

void Font::Destroy()
{
    if (m_font){
        TTF_CloseFont(m_font);
        m_font = 0;
    }
}

int Font::GetHeight()
{
    return TTF_FontHeight(m_font);
}

/* Set and retrieve the font style */
void Font::SetStyle(int style)
{
    TTF_SetFontStyle(m_font, style);
}

void Font::SetStyle(bool bold, bool italic, bool underline, bool strikethrough)
{
    int                 style  = FONT_STYLE_NORMAL;
    if (bold)           style |= FONT_STYLE_BOLD;
    if (italic)         style |= FONT_STYLE_ITALIC;
    if (underline)      style |= FONT_STYLE_UNDERLINE;
    if (strikethrough)  style |= FONT_STYLE_STRIKETHROUGH;
    this->SetStyle(style);
}

int Font::GetStyle()
{
    return TTF_GetFontStyle(m_font);
}

void Font::SetOutline(int outline)
{
    TTF_SetFontOutline(m_font, outline);
}

int  Font::GetOutline()
{
    return TTF_GetFontOutline(m_font);
}

/* Set and retrieve FreeType hinter settings */
void Font::SetHinting(FontHinting hinting)
{
    TTF_SetFontHinting(m_font, (int)hinting);
}

FontHinting Font::GetHinting()
{
    return (FontHinting)TTF_GetFontHinting(m_font);
}

/* Get the offset from the baseline to the top of the font
This is a positive value, relative to the baseline.
*/
int Font::Ascent()
{
    return TTF_FontAscent(m_font);
}

/* Get the offset from the baseline to the bottom of the font
This is a negative value, relative to the baseline.
*/
int Font::Descent()
{
    return TTF_FontDescent(m_font);
}

/* Get the recommended spacing between lines of text for this font */
int Font::LineSkip()
{
    return TTF_FontLineSkip(m_font);
}

/* Get/Set whether or not kerning is allowed for this font */
void Font::SetKerning(bool allowed)
{
    TTF_SetFontKerning(m_font, (allowed ? 1 : 0));
}

int Font::GetKerning()
{
    return TTF_GetFontKerning(m_font);
}

/* Get the number of faces of the font */
long Font::Faces()
{
    return TTF_FontFaces(m_font);
}

/* Get the font face attributes, if any */
int Font::FaceIsFixedWidth()
{
    return TTF_FontFaceIsFixedWidth(m_font);
}

char* Font::FaceFamilyName()
{
    return TTF_FontFaceFamilyName(m_font);
}

char* Font::FaceStyleName()
{
    return TTF_FontFaceStyleName(m_font);
}

/* Check wether a glyph is provided by the font or not */
int Font::GlyphIsProvided(Uint16 ch)
{
    return TTF_GlyphIsProvided(m_font, ch);
}

/* Get the metrics (dimensions) of a glyph
To understand what these metrics mean, here is a useful link:
http://freetype.sourceforge.net/freetype2/docs/tutorial/step2.html
*/
int Font::GlyphMetrics(Uint16 ch, int *minx, int *maxx,
                        int *miny, int *maxy, int *advance)
{
    return TTF_GlyphMetrics(m_font, ch, minx, maxx, miny, maxy, advance);
}

/* Get the dimensions of a rendered string of text */
Size Font::GetSize(const char *text)
{
    Size sz;
    TTF_SizeText(m_font, text, &sz.w, &sz.h);
    return sz;
}

Size Font::GetSizeUTF8(const char *text)
{
    Size sz;
    TTF_SizeUTF8(m_font, text, &sz.w, &sz.h);
    return sz;
}

Size Font::GetSizeUNICODE(const Uint16 *text)
{
    Size sz;
    TTF_SizeUNICODE(m_font, text, &sz.w, &sz.h);
    return sz;
}

/* Get the kerning size of two glyphs */
int Font::GetKerningSizeGlyphs(Uint16 previous_ch, Uint16 ch)
{
    return TTF_GetFontKerningSizeGlyphs(m_font, previous_ch, ch);
}

ITexture* Font::RenderText(IRender* render, const char* text, const Color* fg)
{
    if (!text || !fg) return 0;
    SDL_Color sdlColor = { fg->r, fg->g, fg->b, fg->a };
    SDL_Surface* sdlsurface = TTF_RenderUTF8_Blended( m_font, text, sdlColor);
    if (!sdlsurface) return 0;
    SDL_Texture* sdltexture = SDL_CreateTextureFromSurface(Render::ToRender(render)->GetSDLRender(), sdlsurface);
    SDL_FreeSurface(sdlsurface);
    sdlsurface = 0;
    if (!sdltexture) return 0;

    Texture* texture = Texture:: GetInterface();
    if (texture){
        if (texture->Create(sdltexture)){
            return texture;
        }
        texture->Destroy();
        texture->Release();
        texture = 0;
    }

    // failed
    SDL_DestroyTexture(sdltexture);
    sdltexture = 0;

    return 0;
}

TTF_Font* Font::GetTTFFont() const
{
    return m_font;
}

EDUI_NAMESPACE_END
